// 版权所有2012 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 此文件实现内置函数调用的类型检查。

package types

import (
	"go/ast"
	"go/constant"
	"go/token"
)

// 内置类型检查对id和指定的内置类型的调用
// 报告调用是否有效，结果为*x；
// 但是没有设置x.expr。如果调用无效，则返回结果
// false，并且*x未定义。
// None
func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
	// append是唯一允许使用。。。最后一个论点
	bin := predeclaredFuncs[id]
	if call.Ellipsis.IsValid() && id != _Append {
		check.invalidOp(atPos(call.Ellipsis),
			_InvalidDotDotDot,
			"invalid use of ... with built-in %s", bin.name)
		check.use(call.Args...)
		return
	}

	// 对于len（x）和cap（x），我们需要知道x是否包含任何函数调用或
	// 接收操作。保存/恢复当前设置并将hasCallOrRecv设置为
	// 对于x的计算为false，以便我们可以在以后进行检查。
	// 注意：我们必须在调用exprList之前执行此操作，因为exprList会计算
	// 所有论点。
	if id == _Len || id == _Cap {
		defer func(b bool) {
			check.hasCallOrRecv = b
		}(check.hasCallOrRecv)
		check.hasCallOrRecv = false
	}

	// 确定实际参数
	var arg func(*operand, int) // TODO（gri）不再使用arg getter，而是直接使用xlist
	nargs := len(call.Args)
	switch id {
	default:
		// 使变元getter
		xlist, _ := check.exprList(call.Args, false)
		arg = func(x *operand, i int) { *x = *xlist[i]; x.typ = expand(x.typ) }
		nargs = len(xlist)
		// 计算第一个参数（如果存在）
		if nargs > 0 {
			arg(x, 0)
			if x.mode == invalid {
				return
			}
		}
	case _Make, _New, _Offsetof, _Trace:
		// 参数需要特殊处理
	}

	// 检查参数计数
	{
		msg := ""
		if nargs < bin.nargs {
			msg = "not enough"
		} else if !bin.variadic && nargs > bin.nargs {
			msg = "too many"
		}
		if msg != "" {
			check.invalidOp(inNode(call, call.Rparen), _WrongArgCount, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
			return
		}
	}

	switch id {
	case _Append:
		// 追加（s，x…T）s，其中T是s的元素类型
		// 说明：“变量函数append将零个或多个值x附加到类型的s
		// S、 它必须是切片类型，并返回结果切片（也是S类型）。
		// 值x被传递给类型为…T的参数，其中T是元素类型
		// 和相应的参数传递规则适用。”
		S := x.typ
		var T Type
		if s := asSlice(S); s != nil {
			T = s.elem
		} else {
			check.invalidArg(x, _InvalidAppend, "%s is not a slice", x)
			return
		}

		// 记住已经计算过的参数
		alist := []operand{*x}

		// spec：“作为一种特殊情况，append还接受第一个可赋值参数
		// 键入[]字节，第二个参数为字符串类型，后跟。
		// 此表单追加字符串的字节。
		if nargs == 2 && call.Ellipsis.IsValid() {
			if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
				arg(x, 1)
				if x.mode == invalid {
					return
				}
				if isString(x.typ) {
					if check.Types != nil {
						sig := makeSig(S, S, x.typ)
						sig.variadic = true
						check.recordBuiltinType(call.Fun, sig)
					}
					x.mode = value
					x.typ = S
					break
				}
				alist = append(alist, *x)
				// 失败
			}
		}

		// 通过创建自定义签名检查一般情况
		sig := makeSig(S, S, NewSlice(T)) // []变量签名需要T
		sig.variadic = true
		var xlist []*operand
		// 将[]操作数转换为[]*操作数
		for i := range alist {
			xlist = append(xlist, &alist[i])
		}
		for i := len(alist); i < nargs; i++ {
			var x operand
			arg(&x, i)
			xlist = append(xlist, &x)
		}
		check.arguments(call, sig, nil, xlist) // 放弃结果（我们知道结果类型）
		// 即使check.arguments报告错误，是否继续

		x.mode = value
		x.typ = S
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, sig)
		}

	case _Cap, _Len:
		// 第（x）章
		// len（x）
		mode := invalid
		var typ Type
		var val constant.Value
		switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
		case *Basic:
			if isString(t) && id == _Len {
				if x.mode == constant_ {
					mode = constant_
					val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
				} else {
					mode = value
				}
			}

		case *Array:
			mode = value
			// 说明：“表达式len（s）和cap（s）是常量
			// 如果s的类型是数组或指向数组的指针，则
			// 表达式s不包含通道接收或
			// 函数调用；在这种情况下，不计算s。”
			if !check.hasCallOrRecv {
				mode = constant_
				if t.len >= 0 {
					val = constant.MakeInt64(t.len)
				} else {
					val = constant.MakeUnknown()
				}
			}

		case *Slice, *Chan:
			mode = value

		case *Map:
			if id == _Len {
				mode = value
			}

		case *_Sum:
			if t.is(func(t Type) bool {
				switch t := under(t).(type) {
				case *Basic:
					if isString(t) && id == _Len {
						return true
					}
				case *Array, *Slice, *Chan:
					return true
				case *Map:
					if id == _Len {
						return true
					}
				}
				return false
			}) {
				mode = value
			}
		}

		if mode == invalid && typ != Typ[Invalid] {
			code := _InvalidCap
			if id == _Len {
				code = _InvalidLen
			}
			check.invalidArg(x, code, "%s for %s", x, bin.name)
			return
		}

		x.mode = mode
		x.typ = Typ[Int]
		x.val = val
		if check.Types != nil && mode != constant_ {
			check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
		}

	case _Close:
		// 关闭（c）
		c := asChan(x.typ)
		if c == nil {
			check.invalidArg(x, _InvalidClose, "%s is not a channel", x)
			return
		}
		if c.dir == RecvOnly {
			check.invalidArg(x, _InvalidClose, "%s must not be a receive-only channel", x)
			return
		}

		x.mode = novalue
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(nil, c))
		}

	case _Complex:
		// 复数（x，y）复数
		var y operand
		arg(&y, 1)
		if y.mode == invalid {
			return
		}

		// 转换或检查非类型化参数
		d := 0
		if isUntyped(x.typ) {
			d |= 1
		}
		if isUntyped(y.typ) {
			d |= 2
		}
		switch d {
		case 0:
			// x和y已键入=>无需执行任何操作
		case 1:
			// 只有x是非类型=>转换为y类型
			check.convertUntyped(x, y.typ)
		case 2:
			// 只有y是非类型=>转换为x类型
			check.convertUntyped(&y, x.typ)
		case 3:
			// x和y是非类型=>
			// 1） 如果两者都是常量，请将它们转换为非类型化
			// 浮点数，如果可能，
			// 2） 如果其中一个不是常数（可能是因为
			// 它包含一个尚未键入的移位（转换）
			// 因为他们必须具有
			// 相同类型成功（这将导致错误
			// 因为不允许浮动移动）
			if x.mode == constant_ && y.mode == constant_ {
				toFloat := func(x *operand) {
					if isNumeric(x.typ) && constant.Sign(constant.Imag(x.val)) == 0 {
						x.typ = Typ[UntypedFloat]
					}
				}
				toFloat(x)
				toFloat(&y)
			} else {
				check.convertUntyped(x, Typ[Float64])
				check.convertUntyped(&y, Typ[Float64])
				// x和y现在应该无效，但要保守
				// 请在下面查看
			}
		}
		if x.mode == invalid || y.mode == invalid {
			return
		}

		// 两种参数类型必须相同
		if !check.identical(x.typ, y.typ) {
			check.invalidArg(x, _InvalidComplex, "mismatched types %s and %s", x.typ, y.typ)
			return
		}

		// 参数类型必须是浮点类型
		f := func(x Type) Type {
			if t := asBasic(x); t != nil {
				switch t.kind {
				case Float32:
					return Typ[Complex64]
				case Float64:
					return Typ[Complex128]
				case UntypedFloat:
					return Typ[UntypedComplex]
				}
			}
			return nil
		}
		resTyp := check.applyTypeFunc(f, x.typ)
		if resTyp == nil {
			check.invalidArg(x, _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
			return
		}

		// 如果两个参数都是常量，则结果为常量
		if x.mode == constant_ && y.mode == constant_ {
			x.val = constant.BinaryOp(constant.ToFloat(x.val), token.ADD, constant.MakeImag(constant.ToFloat(y.val)))
		} else {
			x.mode = value
		}

		if check.Types != nil && x.mode != constant_ {
			check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ, x.typ))
		}

		x.typ = resTyp

	case _Copy:
		// 复制（x，y[]T）int
		var dst Type
		if t := asSlice(x.typ); t != nil {
			dst = t.elem
		}

		var y operand
		arg(&y, 1)
		if y.mode == invalid {
			return
		}
		var src Type
		switch t := optype(y.typ).(type) {
		case *Basic:
			if isString(y.typ) {
				src = universeByte
			}
		case *Slice:
			src = t.elem
		}

		if dst == nil || src == nil {
			check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
			return
		}

		if !check.identical(dst, src) {
			check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
			return
		}

		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
		}
		x.mode = value
		x.typ = Typ[Int]

	case _Delete:
		// 删除（m，k）
		m := asMap(x.typ)
		if m == nil {
			check.invalidArg(x, _InvalidDelete, "%s is not a map", x)
			return
		}
		arg(x, 1) // K
		if x.mode == invalid {
			return
		}

		check.assignment(x, m.key, "argument to delete")
		if x.mode == invalid {
			return
		}

		x.mode = novalue
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
		}

	case _Imag, _Real:
		// imag（complexT）float
		// 实（复数）浮点数

		// 转换或检查非类型化参数
		if isUntyped(x.typ) {
			if x.mode == constant_ {
				// 可以始终考虑使用非类型化常量
				// 作为复常数
				if isNumeric(x.typ) {
					x.typ = Typ[UntypedComplex]
				}
			} else {
				// 如果出现以下情况，则可能会出现非类型化的非常量参数：
				// 它包含一个（尚未类型化的非常量）移位
				// 表达式：将其转换为complex128，它将
				// 导致错误（复数值移位）
				check.convertUntyped(x, Typ[Complex128])
				// x现在应该无效，但要保守并检查
				if x.mode == invalid {
					return
				}
			}
		}

		// 参数必须是复杂类型
		f := func(x Type) Type {
			if t := asBasic(x); t != nil {
				switch t.kind {
				case Complex64:
					return Typ[Float32]
				case Complex128:
					return Typ[Float64]
				case UntypedComplex:
					return Typ[UntypedFloat]
				}
			}
			return nil
		}
		resTyp := check.applyTypeFunc(f, x.typ)
		if resTyp == nil {
			code := _InvalidImag
			if id == _Real {
				code = _InvalidReal
			}
			check.invalidArg(x, code, "argument has type %s, expected complex type", x.typ)
			return
		}

		// 如果参数是常量，则结果是常量
		if x.mode == constant_ {
			if id == _Real {
				x.val = constant.Real(x.val)
			} else {
				x.val = constant.Imag(x.val)
			}
		} else {
			x.mode = value
		}

		if check.Types != nil && x.mode != constant_ {
			check.recordBuiltinType(call.Fun, makeSig(resTyp, x.typ))
		}

		x.typ = resTyp

	case _Make:
		// make（T，n）
		// 制造（T，n，m）
		// （尚未评估任何参数）
		arg0 := call.Args[0]
		T := check.varType(arg0)
		if T == Typ[Invalid] {
			return
		}

		min, max := -1, 10
		var valid func(t Type) bool
		valid = func(t Type) bool {
			var m int
			switch t := optype(t).(type) {
			case *Slice:
				m = 2
			case *Map, *Chan:
				m = 1
			case *_Sum:
				return t.is(valid)
			default:
				return false
			}
			if m > min {
				min = m
			}
			if m+1 < max {
				max = m + 1
			}
			return true
		}

		if !valid(T) {
			check.invalidArg(arg0, _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
			return
		}
		if nargs < min || max < nargs {
			if min == max {
				check.errorf(call, _WrongArgCount, "%v expects %d arguments; found %d", call, min, nargs)
			} else {
				check.errorf(call, _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, max, nargs)
			}
			return
		}

		types := []Type{T}
		var sizes []int64 // 常量整型参数（如果有）
		for _, arg := range call.Args[1:] {
			typ, size := check.index(arg, -1) // 可以继续使用typ==typ[无效]
			types = append(types, typ)
			if size >= 0 {
				sizes = append(sizes, size)
			}
		}
		if len(sizes) == 2 && sizes[0] > sizes[1] {
			check.invalidArg(call.Args[1], _SwappedMakeArgs, "length and capacity swapped")
			// 安全地继续
		}
		x.mode = value
		x.typ = T
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
		}

	case _New:
		// 新（T）
		// （尚未评估任何参数）
		T := check.varType(call.Args[0])
		if T == Typ[Invalid] {
			return
		}

		x.mode = value
		x.typ = &Pointer{base: T}
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
		}

	case _Panic:
		// 恐慌（x）
		// 如果在带有结果参数的函数中，则记录紧急调用
		// （用于棋盘格、棋盘格）
		if check.sig != nil && check.sig.results.Len() > 0 {
			// 函数具有结果参数
			p := check.isPanic
			if p == nil {
				// 懒散地分配
				p = make(map[*ast.CallExpr]bool)
				check.isPanic = p
			}
			p[call] = true
		}

		check.assignment(x, &emptyInterface, "argument to panic")
		if x.mode == invalid {
			return
		}

		x.mode = novalue
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(nil, &emptyInterface))
		}

	case _Print, _Println:
		// 打印（x，y，…）
		// println（x，y，…）
		var params []Type
		if nargs > 0 {
			params = make([]Type, nargs)
			for i := 0; i < nargs; i++ {
				if i > 0 {
					arg(x, i) // 第一个参数已计算
				}
				check.assignment(x, nil, "argument to "+predeclaredFuncs[id].name)
				if x.mode == invalid {
					// TODO（gri）“使用”所有参数？
					return
				}
				params[i] = x.typ
			}
		}

		x.mode = novalue
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(nil, params...))
		}

	case _Recover:
		// recover（）接口{}
		x.mode = value
		x.typ = &emptyInterface
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(x.typ))
		}

	case _Add:
		// 不安全的.Add（ptr unsafe.Pointer，len IntegerType）不安全的.Pointer
		if !check.allowVersion(check.pkg, 1, 17) {
			check.errorf(call.Fun, _InvalidUnsafeAdd, "unsafe.Add requires go1.17 or later")
			return
		}

		check.assignment(x, Typ[UnsafePointer], "argument to unsafe.Add")
		if x.mode == invalid {
			return
		}

		var y operand
		arg(&y, 1)
		if !check.isValidIndex(&y, _InvalidUnsafeAdd, "length", true) {
			return
		}

		x.mode = value
		x.typ = Typ[UnsafePointer]
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(x.typ, x.typ, y.typ))
		}

	case _Alignof:
		// （x T）uintpttr的不安全校准
		if asTypeParam(x.typ) != nil {
			check.invalidOp(call, _Todo, "unsafe.Alignof undefined for %s", x)
			return
		}
		check.assignment(x, nil, "argument to unsafe.Alignof")
		if x.mode == invalid {
			return
		}

		x.mode = constant_
		x.val = constant.MakeInt64(check.conf.alignof(x.typ))
		x.typ = Typ[Uintptr]
		// 结果为常量-无需记录签名

	case _Offsetof:
		// 不安全。偏移量为（x T）uintpttr，其中x必须是选择器
		// （尚未评估任何参数）
		arg0 := call.Args[0]
		selx, _ := unparen(arg0).(*ast.SelectorExpr)
		if selx == nil {
			check.invalidArg(arg0, _BadOffsetofSyntax, "%s is not a selector expression", arg0)
			check.use(arg0)
			return
		}

		check.expr(x, selx.X)
		if x.mode == invalid {
			return
		}

		base := derefStructPtr(x.typ)
		sel := selx.Sel.Name
		obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel)
		switch obj.(type) {
		case nil:
			check.invalidArg(x, _MissingFieldOrMethod, "%s has no single field %s", base, sel)
			return
		case *Func:
			// 使用derefStructPtr的TODO（gri）可能会导致找到方法
			// 这实际上并不存在。无论哪种方式都是错误，但是
			// 这个信息令人困惑。请参阅：https:
			// 但是go/types报告：“无效参数：x.m是一个方法值”。
			check.invalidArg(arg0, _InvalidOffsetof, "%s is a method value", arg0)
			return
		}
		if indirect {
			check.invalidArg(x, _InvalidOffsetof, "field %s is embedded via a pointer in %s", sel, base)
			return
		}

		// TODO（gri）我们是否应该通过x.typ而不是base（以及间接报告，如果derefStructPtr是间接的）？
		check.recordSelection(selx, FieldVal, base, obj, index, false)

		offs := check.conf.offsetof(base, index)
		x.mode = constant_
		x.val = constant.MakeInt64(offs)
		x.typ = Typ[Uintptr]
		// 结果为常量-无需记录签名

	case _Sizeof:
		// 不安全尺寸（x T）uintpttr
		if asTypeParam(x.typ) != nil {
			check.invalidOp(call, _Todo, "unsafe.Sizeof undefined for %s", x)
			return
		}
		check.assignment(x, nil, "argument to unsafe.Sizeof")
		if x.mode == invalid {
			return
		}

		x.mode = constant_
		x.val = constant.MakeInt64(check.conf.sizeof(x.typ))
		x.typ = Typ[Uintptr]
		// 结果为常量-无需记录签名

	case _Slice:
		// 不安全的.Slice（ptr*T，len IntegerType）[]T
		if !check.allowVersion(check.pkg, 1, 17) {
			check.errorf(call.Fun, _InvalidUnsafeSlice, "unsafe.Slice requires go1.17 or later")
			return
		}

		typ := asPointer(x.typ)
		if typ == nil {
			check.invalidArg(x, _InvalidUnsafeSlice, "%s is not a pointer", x)
			return
		}

		var y operand
		arg(&y, 1)
		if !check.isValidIndex(&y, _InvalidUnsafeSlice, "length", false) {
			return
		}

		x.mode = value
		x.typ = NewSlice(typ.base)
		if check.Types != nil {
			check.recordBuiltinType(call.Fun, makeSig(x.typ, typ, y.typ))
		}

	case _Assert:
		// 如果pred为false，则assert（pred）会导致typechecker错误。
		// 如果没有错误，assert的结果就是pred的值。
		// 注意：断言仅在自检模式下可用。
		if x.mode != constant_ || !isBoolean(x.typ) {
			check.invalidArg(x, _Test, "%s is not a boolean constant", x)
			return
		}
		if x.val.Kind() != constant.Bool {
			check.errorf(x, _Test, "internal error: value of %s should be a boolean constant", x)
			return
		}
		if !constant.BoolVal(x.val) {
			check.errorf(call, _Test, "%v failed", call)
			// 编译时断言失败-可以安全地继续
		}
		// 结果为常量-无需记录签名

	case _Trace:
		// 跟踪（x，y，z，…）转储位置、表达式和
		// 其参数的值。跟踪的结果是值
		// 第一个论点。
		// 注意：跟踪仅在自检模式下可用。
		// （尚未评估任何参数）
		if nargs == 0 {
			check.dump("%v: trace() without arguments", call.Pos())
			x.mode = novalue
			break
		}
		var t operand
		x1 := x
		for _, arg := range call.Args {
			check.rawExpr(x1, arg, nil) // 允许跟踪类型，例如：新（跟踪（T））
			check.dump("%v: %s", x1.Pos(), x1)
			x1 = &t // 仅对第一个参数使用传入的x
		}
		// 跟踪仅在测试模式下可用-无需记录签名

	default:
		unreachable()
	}

	return true
}

// applyTypeFunc将f应用于x。如果x是类型参数，
// 结果是一个由新的
// 接口绑定。该接口的类型边界
// 通过将f应用于每个类型边界来计算
// x。如果f的任何应用返回零，
// applyTypeFunc返回nil。
// 如果x不是类型参数，则结果为f（x）。
func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
	if tp := asTypeParam(x); tp != nil {
		// 测试t是否满足参数的要求
		// 同时键入和收集可能的结果类型。
		var rtypes []Type
		if !tp.Bound().is(func(x Type) bool {
			if r := f(x); r != nil {
				rtypes = append(rtypes, r)
				return true
			}
			return false
		}) {
			return nil
		}

		// 构造合适的新类型参数
		tpar := NewTypeName(token.NoPos, nil /* = Universe pkg */, "<type parameter>", nil)
		ptyp := check.newTypeParam(tpar, 0, &emptyInterface) // 将类型指定给tpar作为副作用
		tsum := _NewSum(rtypes)
		ptyp.bound = &Interface{types: tsum, allMethods: markComplete, allTypes: tsum}

		return ptyp
	}

	return f(x)
}

// makeSig为给定的参数和结果类型生成签名。
// 默认类型用于非类型化参数，res可以为nil。
func makeSig(res Type, args ...Type) *Signature {
	list := make([]*Var, len(args))
	for i, param := range args {
		list[i] = NewVar(token.NoPos, nil, "", Default(param))
	}
	params := NewTuple(list...)
	var result *Tuple
	if res != nil {
		assert(!isUntyped(res))
		result = NewTuple(NewVar(token.NoPos, nil, "", res))
	}
	return &Signature{params: params, results: result}
}

// 如果类型的形式为*A且A是数组，则implicitArrayDeref返回A；
// 否则返回typ。
// None
func implicitArrayDeref(typ Type) Type {
	if p, ok := typ.(*Pointer); ok {
		if a := asArray(p.base); a != nil {
			return a
		}
	}
	return typ
}

// unparen返回e，并去掉任何括号。
func unparen(e ast.Expr) ast.Expr {
	for {
		p, ok := e.(*ast.ParenExpr)
		if !ok {
			return e
		}
		e = p.X
	}
}
